/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */

package com.jellyfishumbrella.GL;

import static org.lwjgl.opengl.GL11.*;
import static org.lwjgl.opengl.GL12.*;
import static org.lwjgl.opengl.GL13.*;
import static org.lwjgl.opengl.GL15.*;
import static org.lwjgl.opengl.GL20.*;
import static org.lwjgl.opengl.GL21.*;
import static org.lwjgl.opengl.GL30.*;
import static org.lwjgl.opengl.GL31.*;
import static org.lwjgl.opengl.GL32.*;
import static org.lwjgl.opengl.GL33.*;
import static org.lwjgl.opengl.GL40.*;
import static org.lwjgl.util.glu.GLU.*;
import static org.lwjgl.util.glu.GLU.*;
import static org.lwjgl.util.glu.GLU.*;
import java.nio.*;

import org.lwjgl.BufferUtils;
import org.lwjgl.util.vector.*;
import java.util.*;

/**
 * 
 * @author Rich Helvey
 * 
 *         Keep all the openGL stuff in here. Pass floatBuffers(or whatever)
 *         into the methods from any sub-classes
 *         who will be responsible for holding the client-side data themselves
 * 
 * 
 * 
 */
public class MeshGL extends AnimObject {
	public int						VAO_Index;
	public int						NUM_ELEMENTS;

	protected static final int		NUM_VBOS		= 1;
	protected static FloatBuffer[]	vertexData		= new FloatBuffer[NUM_VBOS];
	protected ShortBuffer[]			vertexOrder		= new ShortBuffer[NUM_VBOS];
	protected int[]					vertexVBO_Index	= new int[NUM_VBOS];
	protected static String[][]		shaderFiles		= null;

	protected Material[]			materials;
	protected Shaders[]				shaders;
	protected boolean[]				useShaders;

	public MeshGL() {
		super();
	}

	public void initGPU() {// FloatBuffer[] vertexData, ShortBuffer[]
							// vertexOrder, int[] bufferIndex, Material[]
							// materials, String[][] shaderFiles) {
		NUM_ELEMENTS = vertexVBO_Index.length;
		setupVAO();
		createVBO(vertexVBO_Index);
		uploadVBO(vertexData, vertexVBO_Index);
		setupMaterials(materials, shaderFiles);
	}

	public void setupVAO() {
		VAO_Index = glGenVertexArrays();
		glBindVertexArray(VAO_Index);
	}

	private void createVBO(int[] bufferIndex) {
		for (int i = 0; i < NUM_ELEMENTS; i++) {
			bufferIndex[i] = glGenBuffers();
		}
	}

	private void uploadVBO(FloatBuffer[] vertexData, int[] bufferIndex) {
		for (int i = 0; i < NUM_ELEMENTS; i++) {
			glBindBuffer(GL_ARRAY_BUFFER, bufferIndex[i]);
			glBufferData(GL_ARRAY_BUFFER, vertexData[i], GL_STATIC_DRAW);
			vertexData[i] = null;
		}
	}

	public void setupMaterials(Material[] mats, String[][] shaderFiles) {
		materials = mats.clone();
		shaders = new Shaders[NUM_ELEMENTS];
		useShaders = new boolean[NUM_ELEMENTS];

		for (int i = 0; i < NUM_ELEMENTS; i++) {
			String vert = shaderFiles[i][0];
			String frag = shaderFiles[i][1];
			shaders[i] = new Shaders(vert, frag);
			useShaders[i] = shaders[i].useShader;
		}
	}

	public void renderAdv() {
		int stride = (3 + 3) * 4; // 3 for Pos, 3 for normal, 4 for bytes
		glPushMatrix();
		glTranslatef(pos.x, pos.y, pos.z);

		glEnableClientState(GL_NORMAL_ARRAY);
		glEnableClientState(GL_VERTEX_ARRAY);
		glEnable(GL_PRIMITIVE_RESTART);

		glPrimitiveRestartIndex(Short.MAX_VALUE);

		for (int i = 0; i < NUM_ELEMENTS; i++) {
			materials[i].render();

			int loc;

			if (useShaders[i]) {
				shaders[i].use();
			}

			glBindBuffer(GL_ARRAY_BUFFER, vertexVBO_Index[i]);
			int offset = 0;
			glVertexPointer(3, GL_FLOAT, stride, offset);
			offset = 3 * 4;
			glNormalPointer(GL_FLOAT, stride, offset);


			glPolygonMode(GL_FRONT_AND_BACK, GL_POINT);
			glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
			glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
			glDrawElements(GL_TRIANGLE_FAN, vertexOrder[i]);
			glPointSize(4);
			if (useShaders[i]) {
				shaders[i].release();
			}
		}

		glDisableClientState(GL_NORMAL_ARRAY);
		glDisableClientState(GL_VERTEX_ARRAY);

		glPopMatrix();
	}
}
